﻿/* $RCSFile: Online.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/CRMWrapper3/Authentication/Online.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:32  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Diagnostics;
using System.Globalization;
using System.Web.Configuration;
using System.Web;
using System.Web.Services.Protocols;
using System.Security.Cryptography.X509Certificates;

using AddonNice.Settings;
using AddonNice.Security;
using AddonNice.CRMWrapper;
using AddonNice.CRMWrapper.CRM4Server;
using AddonNice.CRMWrapper.CRM4ADDisco;

// Import the Microsoft Dynamics CRM namespaces.
//using Microsoft.Crm.Sdk;
//using Microsoft.Crm.Sdk.Query;

namespace AddonNice.CRMWrapper.Authentication
{
    /// <summary>
    /// Authentication without using any certificate for Microsoft Dynamics CRM Online.
    /// </summary>
    public class Online : CrmAuthenticationBase
    {
        
        protected string _userWlidTicket                    =   string.Empty;
        public string userWlidTicket
        {
            get
            {
                return _userWlidTicket;
            }
        }

        protected string _adminWlidTicket                    =   string.Empty;
        public string adminWlidTicket
        {
            get
            {
                if ( _adminWlidTicket == string.Empty )
                    _adminWlidTicket    =   RetrieveWLIDTicket(CRMServiceAccount,CRMServicePassword);
                return _adminWlidTicket;
            }
        }

        protected string _adminCrmTicket                    =   string.Empty;
        public string adminCrmTicket
        {
            get
            {
                if ( _adminCrmTicket == string.Empty )
                    _adminCrmTicket    =   RetrieveCrmTicket(adminWlidTicket,ref _adminCrmTicketExpirationDate);
                return _adminCrmTicket;
            }
        }

        protected string _adminCrmTicketExpirationDate      =   string.Empty;
        public string adminCrmTicketExpirationDate
        {
            get
            {
                return _adminCrmTicketExpirationDate;
            }
        }

        public override string UrlDisco
        {
            get
            {
                return string.Format("https://{0}/MSCRMServices/2007/Passport/CrmCrmDisco.asmx",CRMOnlineHostname);
            }
        }

        public override CrmDiscoveryService CrmDisco
        {
            get
            {
                if (_CrmDisco == null)
                {
                    _CrmDisco                           =   new CrmDiscoveryService();
                    _CrmDisco.Url                       =   UrlDisco;
                }
                return _CrmDisco;
            }
        }

        #region Configuration data
        
        // TODO: Use characters allowed by WLID. This was not defined when this sample was written.
        private string _devicePassword = "user-supplied-device-pswd"; 
        public string devicePassword
        {
            get { return _devicePassword; }
            set { _devicePassword = value; }
        }

        // Set the name ( and if TCP port) of the server hosting Microsoft Dynamics CRM Online.
        private string _CRMOnlineHostname            =   Config.CRMOnlineHostname;
        public string CRMOnlineHostname
        {
            get { return _CRMOnlineHostname; }
            set { _CRMOnlineHostname = value; }
        }

        // This is the authentication policy.
        static private string _policy       =   "MBI_SSL";

        // This is open information about CRM Online.
        static private string _partner  =    "crm.dynamics.com";

        // Set the type of Environment.
        static private LiveIdTicketManager.LiveIdEnvironment _environment   =   LiveIdTicketManager.LiveIdEnvironment.PROD;

        #endregion Configuration data

        // Defines the expired authentication ticket error code.
        static private string EXPIRED_AUTH_TICKET = "8004A101";

        // Attempt a service call a maximum number of times before failing.
        private int _MaxRetries = 5;
        public int MaxRetries
        {
            get { return _MaxRetries; }
            set { _MaxRetries = value; }
        }


        public override bool IsUserOk4Crm(string domain,string login,string pwd)
        {
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]Online IsUserOk4Crm BEG.",CRMTraceSwitch.Sw.Info);
            bool ret                            =   false;
            try
            {
                WhoAmIRequest request1		=   new WhoAmIRequest();
                string wlidticket           =   RetrieveWLIDTicket(login,pwd);
                string expDate              =   string.Empty;
                string crmticket            =   RetrieveCrmTicket(wlidticket,ref expDate);
                if ( !string.IsNullOrEmpty(crmticket) )
                {
                    Crm4WebService TestService	=	new Crm4WebService(ServiceUrl,false,MakeToken(crmticket),OrganizationName);
			        if ( CRMTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online IsUserCredentialsOk Service Ok url: {0}",ServiceUrl),CRMTraceSwitch.Sw.Info);
                    TestService.ExecuteRaw(request1);
                    ret                         =   true;
                }
            }
            catch (Exception ex)
            {
                string msg  =   string.Format("[E]Online IsUserOk4Crm ex: {0}.", ex);
                if ( CRMTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
            }
			if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online IsUserOk4Crm END: {0}",ret),CRMTraceSwitch.Sw.Info);
            return ret;       
        }

        protected string _userCrmTicket                     =   string.Empty;
        protected string _userCrmTicketExpirationDate       =   string.Empty;
        /// <summary>
		/// Mode SPLA ticket used for the userService
		/// Addon Nice authentication mode is necessarely forms, depends on:
		/// - if user authenticated, new credentials will be created from the current authenticated user, see AddonNiceIdentity
		/// - if not authenticated (anonymous), new credentials will be used from default crm user set in web.config
		/// </summary>
        public string userCrmTicket
        {
            get
            {
                if (_userCrmTicket == string.Empty)
                {
                    if ( CRMTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( "[V]Online userCrmTicket GET BEG.",CRMTraceSwitch.Sw.Info);
                    try
                    {
						AuthenticationMode auth	        =	Config.AuthenticationMode;
						if ( CRMTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online userCrmTicket authenticationMode: {0}", auth),CRMTraceSwitch.Sw.Info);
						if ( auth != AuthenticationMode.Forms )
						{
                            throw new CRMWrapperException("Addon Nice is in Windows authentication, this is not valid for Online");
						}
                        // Authentication == Forms
                        if (HttpContext.Current.Request.IsAuthenticated 
                            && ( HttpContext.Current.User.Identity is AddonNiceIdentity ))// <- when in first setup we could have a FormIdentity
                        {
		                    if ( CRMTraceSwitch.Sw.TraceVerbose )
                                Trace.WriteLine( "[V]Online userCrmTicket Forms Mode, IsAuthenticated true.",CRMTraceSwitch.Sw.Info);
                            AddonNiceIdentity AId   =   (AddonNiceIdentity)HttpContext.Current.User.Identity;
                            _userWlidTicket         =   RetrieveWLIDTicket(string.Format("{0}\\{1}",AId.CrmImpersonateDomain,AId.CrmImpersonateLogin),AId.CrmImpersonatePwd);
                            _userCrmTicket          =   RetrieveCrmTicket(_userWlidTicket,ref _userCrmTicketExpirationDate);
                        }
                        else // If we are in Forms authentication with non authenticated user, we need some default account to logon
                        {
                            if ( CRMTraceSwitch.Sw.TraceVerbose )
                                Trace.WriteLine(
                                string.Format("[V]Online userCrmTicket Forms Mode not authenticated getting credentials from default values to allow logon: {0}-{1}-{2}.", 
                                    CRMServiceDefaultAccount,CRMServiceDefaultPassword,CRMServiceDefaultDomain),CRMTraceSwitch.Sw.Info);
                            // if not authenticated use default values
                            _userWlidTicket         =   RetrieveWLIDTicket(string.Format("{0}\\{1}",CRMServiceDefaultDomain,CRMServiceDefaultAccount),CRMServiceDefaultPassword);
                            _userCrmTicket          =   RetrieveCrmTicket(_userWlidTicket,ref _userCrmTicketExpirationDate);
                         }
                    }
                    catch (Exception ex)
                    {
                        string msg                  =   string.Format(CultureInfo.InvariantCulture,"[E]Online userCrmTicket ex: {0}", ex);
                        if ( CRMTraceSwitch.Sw.TraceError )
                            Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                        throw new CRMWrapperException(msg, ex);
                    }
                }
                if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine(string.Format("[V]Online userCrmTicket END ticket: '{0}'.",_userCrmTicket),CRMTraceSwitch.Sw.Info);
                return _userCrmTicket;
            }
        }

        /// <summary>
        /// Authenticates a user with Microsoft Dynamics CRM Online. Afterwards,
        /// a call to a CrmService Web method is attempted to verify that the
        /// authentication was valid.
        /// </summary>
        /// <returns>True if successfull, otherwise false.</returns>
        public string RetrieveWLIDTicket(string userName,string pwd)
        {
            if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine(string.Format("[V]Online RetrieveWLIDTicket BEG userName: '{0}'.",userName),CRMTraceSwitch.Sw.Info);
            string wlidTicket            =   string.Empty;
            try
            {
                wlidTicket            =   LiveIdTicketManager.RetrieveTicket(_devicePassword, _partner,userName, pwd, _policy, _environment);
                if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine(string.Format("[V]Online RetrieveWLIDTicket END wlidTicket: '{0}'.",wlidTicket),CRMTraceSwitch.Sw.Info);
            }

            // Handle any Web service exceptions that might be thrown.
            catch (SoapException ex)
            {
                string msg  =   string.Format("[E]Online RetrieveWLIDTicket sex: {0}.", ex);
                if ( CRMTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                throw;
                
            }
            catch (Exception ex)
            {
                string msg  =   string.Format("[E]Online RetrieveWLIDTicket ex: {0}.", ex);
                if ( CRMTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                throw;
            }

            return wlidTicket;
        }

        public string RetrieveCrmTicket(string wlidTicket,ref string ExpirationDate)
        {
            if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online RetrieveCrmTicket BEG wlidTicket: '{0}'.",wlidTicket),CRMTraceSwitch.Sw.Info);
            string ticket                    =   string.Empty;
            try
            {
                // Retrieve the CrmTicket
                RetrieveCrmTicketRequest crmTicketRequest   =   new RetrieveCrmTicketRequest();
                crmTicketRequest.OrganizationName           =   OrganizationName;
                crmTicketRequest.PassportTicket             =   wlidTicket; 
                RetrieveCrmTicketResponse crmTicketResponse =   (RetrieveCrmTicketResponse)CrmDisco.Execute(crmTicketRequest);
                ticket                                      =   crmTicketResponse.CrmTicket;
                ExpirationDate                              =   crmTicketResponse.ExpirationDate;
                }
            catch (Exception ex)
            {
                string msg  =   string.Format("[E]Online RetrieveCrmTicket ex: {0}.", ex);
                if ( CRMTraceSwitch.Sw.TraceError )
                    Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                throw;
            }
            if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online RetrieveCrmTicket END ticket: '{0}'.",ticket),CRMTraceSwitch.Sw.Info);
            return ticket;
        }      

        public CrmAuthenticationToken MakeToken(string CrmTicket)
        {
            if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online MakeToken BEG CrmTicket: '{0}'.",CrmTicket),CRMTraceSwitch.Sw.Info);
            CrmAuthenticationToken token                =   new CrmAuthenticationToken();
            token.AuthenticationType                    =   Microsoft.Crm.Sdk.AuthenticationType.Passport;
            token.CrmTicket                             =   CrmTicket;
            token.OrganizationName                      =   OrganizationName;
            return token;
        }      

        public override bool FindOrganization(string orgName)
        {
            if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online FindOrganization BEG orgName: '{0}'.",orgName),CRMTraceSwitch.Sw.Info);
            string onlineTicket                                 =   adminWlidTicket;
            if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online FindOrganization adminWlidTicket: '{0}'.",onlineTicket),CRMTraceSwitch.Sw.Info);
            int firstAttempt                                    =   1;
            while ( firstAttempt < MaxRetries )
            {
                try
                {
                    foreach (OrganizationDetail orgDetail in Organizations)
                    {
                        if ( orgDetail.OrganizationName.Equals(orgName) )
                        {
                            if ( CRMTraceSwitch.Sw.TraceVerbose )
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online FindOrganization found orgName: {0}, CrmServiceUrl: {1}, CrmMetadataServiceUrl: {2}.",
                                    orgName,orgDetail.CrmServiceUrl,orgDetail.CrmMetadataServiceUrl),CRMTraceSwitch.Sw.Info);
                            Organization                            =   orgDetail;
                            OrganizationName                        =   orgDetail.OrganizationName;
                            OrganizationFriendlyName                =   orgDetail.FriendlyName;
                            ServiceUrl                              =   orgDetail.CrmServiceUrl;
                            MetaDataServiceUrl                      =   orgDetail.CrmMetadataServiceUrl;
                            WebApplicationUrl                       =   orgDetail.WebApplicationUrl;
                            OrganizationId                          =   orgDetail.OrganizationId;
                            return true;
                        }
                    }
                }
                catch (SoapException ex)
                {
                    string msg                                      =   string.Format("[E]Online FindOrganization sex: {0}.", ex);
                    if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                    // Handle the exception thrown from an expired ticket condition.
                    if (GetErrorCode(ex.Detail) == EXPIRED_AUTH_TICKET)
                    {
                       firstAttempt++;
                    }
                    else throw;
                }
                catch (Exception ex)
                {
                    string msg                                      =   string.Format("[E]Online FindOrganization ex: {0}.", ex);
                    if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                    throw;
                }
            }
            if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online FindOrganization END NOT FOUND orgName: '{0}'.",orgName),CRMTraceSwitch.Sw.Info);
            return false;
        }

        /// <summary>
        /// Returns the error code that is contained in SoapException.Detail.
        /// </summary>
        /// <param name="errorInfo">An XmlNode that contains application specific error information.</param>
        /// <returns>Error code text or empty string.</returns>
        private static string GetErrorCode(XmlNode errorInfo)
        {
            XmlNode code = errorInfo.SelectSingleNode("//code");

            if (code != null)
                return code.InnerText;
            else
                return string.Empty;
        }

        /// <summary>
        /// Retrieve with disco service list of all org managed on this CRM server
        /// </summary>
        public override List<OrganizationDetail> Organizations
        {
            get
            {
                if ( (_Organizations == null) || (_Organizations.Count == 0 ))
                {
                    try
                    {
                        _Organizations                              =   new List<OrganizationDetail>();
                        RetrieveOrganizationsRequest orgRequest     =   new RetrieveOrganizationsRequest();
                        orgRequest.PassportTicket                   =   adminWlidTicket;

                        RetrieveOrganizationsResponse orgResponse   =   (RetrieveOrganizationsResponse)CrmDisco.Execute(orgRequest);

                        foreach (OrganizationDetail orgDetail in orgResponse.OrganizationDetails)
                        {
                            if ( CRMTraceSwitch.Sw.TraceVerbose )
                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online Organizations GET found Organization: {0}",
                                    orgDetail.OrganizationName),CRMTraceSwitch.Sw.Info);
                            _Organizations.Add(orgDetail);
                        }
                        if ( CRMTraceSwitch.Sw.TraceVerbose )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online Organizations GET Count: {0}",_Organizations.Count),CRMTraceSwitch.Sw.Info);
                    }
                    catch (Exception ex)
                    {
                        string msg                                  =   string.Format("[E]Online Organizations GET ex: {0}", ex);
                        if ( CRMTraceSwitch.Sw.TraceError )
                            Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                        throw new CRMWrapperException(msg, ex);
                    }
                }
                return _Organizations;
           }
        }
        /// <summary>
        /// Called by Ctor to create Admin crmservice objects necessary to first Crm calls with admin mode
        /// </summary>
        public override void InitAdminService(bool UsePreAuthenticate)
        {
            if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]Online InitAdminService BEG.",CRMTraceSwitch.Sw.Info);
            if (_adminAdminService == null)
            {
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online InitAdminService adminAdminService START OrganizationName: {0}",OrganizationName),CRMTraceSwitch.Sw.Info);
                try
                {
                    _adminAdminService			=	new Crm4WebService(ServiceUrl,UsePreAuthenticate,adminCrmTicket,OrganizationName);
					if ( CRMTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online InitAdminService _adminAdminService Ok url: {0}",ServiceUrl),CRMTraceSwitch.Sw.Info);
                }
                catch (SoapException sx)
                {
                    string msg                  =   string.Format("[E]Online InitAdminService adminAdminService sx : {0}-{1}", sx, sx.Detail.InnerText);
                    if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                    throw new CRMWrapperException(msg, sx);
                }
                catch (CRMWrapperException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    string msg                  =   string.Format("[E]Online InitAdminService adminAdminService ex: {0}", ex);
                    if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                    throw new CRMWrapperException(msg, ex);
                }
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( "[V]Online InitAdminService adminAdminService END ok",CRMTraceSwitch.Sw.Info);
            }
            if (_adminService == null)
            {
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( "[V]Online InitAdminService _adminService start",CRMTraceSwitch.Sw.Info);
                try
                {
                    _adminService			    =	adminAdminService;
                    //if ( CRMTraceSwitch.Sw.TraceVerbose )
                    //    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online InitAdminService _adminService.CallerIdValue : {0}", adminUserId),CRMTraceSwitch.Sw.Info);
                }
                catch (SoapException sx)
                {
                    string msg                  =   string.Format(CultureInfo.InvariantCulture,"[E]Online InitAdminService adminService sx : {0}-{1}", sx, sx.Detail.InnerText);  
                    if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                    throw new CRMWrapperException(msg, sx);
                }
                catch (CRMWrapperException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]Online InitAdminService adminService ex: {0}", ex),CRMTraceSwitch.Sw.Info);
                    throw new CRMWrapperException("adminService ex", ex);
                }
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( "[V]Online InitAdminService _adminService end",CRMTraceSwitch.Sw.Info);
            }
			if ( _adminMetaService == null )
            {
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( "[V]Online InitAdminService _adminMetaService start",CRMTraceSwitch.Sw.Info);
                try
                {
                    _adminMetaService		        =	new Crm4MetadataWebService(MetaDataServiceUrl,true,adminCrmTicket,OrganizationName);
                    if ( CRMTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( "[V]Online InitAdminService _adminMetaService Ok",CRMTraceSwitch.Sw.Info);
                }
                catch (SoapException sx)
                {
                    if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]Online InitAdminService _adminMetaService sx : {0}-{1}", sx, sx.Detail.InnerText),CRMTraceSwitch.Sw.Info);
                    throw new CRMWrapperException("adminMetaService soap: " + sx.Detail.InnerText, sx);
                }
                catch (CRMWrapperException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]Online InitAdminService _adminMetaService ex: {0}", ex),CRMTraceSwitch.Sw.Info);
                    throw new CRMWrapperException("adminMetaService ex", ex);
                }
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( "[V]Online InitAdminService _adminMetaService end",CRMTraceSwitch.Sw.Info);
            }

            // We need this to call wrapper only after Application_AuthenticateRequest has run
            // if Application_AuthenticateRequest is not runned we can get the Http.Context.Current.User and never reach this point
             if ( CRMTraceSwitch.Sw.TraceVerbose )
                 Trace.WriteLine( "[V]Online InitAdminService END Ok",CRMTraceSwitch.Sw.Info);
        }
        
        /// <summary>
        /// Called by startWrapper to create different crmservice objects necessary to further running
        /// </summary>
        public override void InitServices(bool UsePreAuthenticate)
        {
            if ( CRMTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( "[V]Online InitServices BEG.",CRMTraceSwitch.Sw.Info);
            if (_userService == null)
            {
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( "[V]Online InitServices _userService START",CRMTraceSwitch.Sw.Info);
                try
                {
                    _userService				=	new Crm4WebService(ServiceUrl,UsePreAuthenticate,userCrmTicket,OrganizationName);
					if ( CRMTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online InitServices _userService Ok url: {0}",ServiceUrl),CRMTraceSwitch.Sw.Info);
                }
                catch (SoapException sx)
                {
                    string msg                  =   string.Format("[E]Online InitServices userService ex: {0}-{1}", sx, sx.Detail.InnerText);
                    if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                    throw new CRMWrapperException(msg, sx);
                }
                catch (CRMWrapperException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    string msg                  =   string.Format("[E]Online InitServices userService ex: {0}", ex);
                    if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
                    throw new CRMWrapperException(msg, ex);
                }
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( "[V]Online InitServices _userService END",CRMTraceSwitch.Sw.Info);
            }
			if (_userMetaService == null)
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( "[V]Online InitServices _userMetaService start",CRMTraceSwitch.Sw.Info);
				try
				{
                    _userMetaService		    =	new Crm4MetadataWebService(MetaDataServiceUrl,UsePreAuthenticate,userCrmTicket,OrganizationName);
					if ( CRMTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]Online InitServices _userMetaService Ok url: {0}",MetaDataServiceUrl),CRMTraceSwitch.Sw.Info);
				}
				catch (SoapException sx)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]Online InitServices _userMetaService sx : {0}-{1}", sx, sx.Detail.InnerText),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("userMetaService soap: " + sx.Detail.InnerText, sx);
				}
				catch (CRMWrapperException)
				{
					throw;
				}
				catch (Exception ex)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]Online InitServices _userMetaService ex: {0}", ex),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("userMetaService ex", ex);
				}
				if ( CRMTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( "[V]Online InitServices _userMetaService end",CRMTraceSwitch.Sw.Info);
			}

            // We need this to call wrapper only after Application_AuthenticateRequest has run
            // if Application_AuthenticateRequest is not runned we can get the Http.Context.Current.User and never reach this point
             if ( CRMTraceSwitch.Sw.TraceVerbose )
                 Trace.WriteLine( "[V]Online InitServices END Ok",CRMTraceSwitch.Sw.Info);
        }
        
        public Online(CrmWrapper4 wrp) : base(wrp)
        {
             if ( CRMTraceSwitch.Sw.TraceVerbose )
                 Trace.WriteLine( "[V]Online Ctor Called",CRMTraceSwitch.Sw.Info);
        }

    }
}
